/* eslint-disable @typescript-eslint/no-explicit-any */
import { getToken } from "@/utils/cached"
import kycRequiredMethods from "@/features_signal/kycRequiredMethods"
import { PATHS } from "@/router/routes"
import { PayloadFormatter } from "@/utils/format"
import { createLogger } from "@/utils/logger"
import { useCallback, useMemo } from "react"
import { Navigate, useLocation, useMatch, useNavigate, useSearchParams } from "react-router-dom"

const logger = createLogger("useSearchAction")

export function useSearchAction() {
    const location = useLocation()
    const [searchParams, setSearchParams] = useSearchParams()

    const setAction = useCallback(
        (action: SearchAction.Action, payload?: Record<string, any>) => {
            setSearchParams((prev) => {
                const newParams = new URLSearchParams(prev)
                newParams.set("action", action)
                if (payload) {
                    newParams.set("payload", PayloadFormatter.encode(payload))
                }
                return newParams
            }, { replace: true, state: location.state })
        },
        [setSearchParams],
    )

    const clearAction = useCallback(() => {
        setSearchParams(
            (prev) => {
                const newParams = new URLSearchParams(prev)
                newParams.delete("action")
                newParams.delete("payload")
                return newParams
            },
            { replace: true, state: location.state },
        )
    }, [setSearchParams])

    const action = searchParams.get("action")
    const payload = searchParams.get("payload")

    const parsedPayload = payload ? PayloadFormatter.decode(payload) : null

    const NavigateAction = useCallback(
        (action: SearchAction.Action, payload?: Record<string, any>) => {
            const searchString = new URLSearchParams()
            searchString.set("action", action)
            if (payload) {
                searchString.set("payload", PayloadFormatter.encode(payload))
            }

            return (
                <Navigate
                    to={{
                        pathname: PATHS.LOGIN,
                        search: searchString.toString(),
                    }}
                    replace
                />
            )
        },
        [],
    )

    return {
        action,
        payload: parsedPayload,
        setAction,
        clearAction,
        NavigateAction,
    }
}

export function useNavigateAction() {
    const navigate = useNavigate()
    const [searchParams] = useSearchParams()
    const match = useMatch("/:root")

    const navigateWithPayload = useCallback(
        (path: string, payload?: Record<string, any>) => {
            navigate({
                pathname: path,
                search: new URLSearchParams({
                    ...(payload ? { payload: PayloadFormatter.encode(payload) } : {}),
                }).toString(),
            })
        },
        [navigate],
    )

    const action = useMemo<SearchAction.Action | null>(() => {
        switch (match?.params.root) {
            case PATHS.LOGIN:
                return "login"
            default:
                return null
        }
    }, [match])
    const payload = searchParams.get("payload")
    const parsedPayload = payload ? PayloadFormatter.decode(payload) : null

    return {
        action,
        payload: parsedPayload,
        navigateWithPayload,
    }
}

type LoginStep = "login-otp-1" | "login-otp-2" | "login-password" | "login-success"

export function useLoginAction() {
    const location = useLocation()
    const navigate = useNavigate()
    const {
        //
        navigateWithPayload,
    } = useNavigateAction()
    const {
        //
        setAction,
        clearAction,
    } = useSearchAction()

    type PayloadData = {
        otpId?: string
        countryCode?: string
        number?: string
    }

    const [searchParams, setSearchParams] = useSearchParams({
        payload: PayloadFormatter.encode({
            step: "login-otp-1",
        }),
    })

    const mode = useMemo<"modal" | "page" | null>(() => {
        return searchParams.get("action") === "login" ? "modal" : "page"
    }, [searchParams])

    const openModalToStep = useCallback(
        (step: LoginStep, data?: PayloadData) => {
            setAction("login", { step, data })
        },
        [setAction],
    )

    const navToStep = useCallback(
        (step: LoginStep, data?: PayloadData) => {
            navigateWithPayload(PATHS.LOGIN, { step, data })
        },
        [navigateWithPayload],
    )

    const payload = useMemo<{
        step: LoginStep
        data?: PayloadData
    }>(() => {
        try {
            const payload = PayloadFormatter.decode(searchParams.get("payload") || "{}")
            return payload as {
                step: LoginStep
                data?: PayloadData
            }
        } catch (error) {
            return {
                step: "login-otp-1",
                data: {},
            }
        }
    }, [searchParams])

    const step = useMemo(() => {
        try {
            return payload.step
        } catch (error) {
            return "login-otp-1" as LoginStep
        }
    }, [payload.step])

    const moveToStep = useCallback(
        (step: LoginStep, data?: PayloadData) => {
            setSearchParams(
                (prev) => {
                    const newParams = new URLSearchParams(prev)
                    const action = newParams.get("action")
                    if (action) {
                        newParams.set("action", action)
                    }
                    newParams.set("payload", PayloadFormatter.encode({ step, data }))
                    return newParams
                },
                {
                    state: location.state,
                },
            )
        },
        [location.state, setSearchParams],
    )

    const setPayload = useCallback(
        (data: PayloadData) => {
            setSearchParams(
                (prev) => {
                    const newParams = new URLSearchParams(prev)
                    newParams.set("payload", PayloadFormatter.encode({ ...payload, data }))
                    return newParams
                },
                {
                    replace: true,
                    state: location.state,
                },
            )
        },
        [setSearchParams, location.state, payload],
    )

    const close = useCallback(() => {
        switch (mode) {
            case "modal":
                clearAction()
                break
            case "page":
                navigate(PATHS.INDEX)
                break
        }
    }, [clearAction, mode, navigate])

    const loginSuccess = useCallback(() => {
        if (mode === "modal") {
            clearAction()
        }
        navigate(
            {
                pathname: location.state?.from ?? PATHS.INDEX,
                search: location.state?.search,
            },
            {
                replace: true,
            },
        )
        kycRequiredMethods.execute("afterLogin")
    }, [mode, navigate, location.state?.from, location.state?.search, clearAction])

    const LoginRedirectNavigate = useMemo(() => {
        const searchString = new URLSearchParams()
        searchString.set("action", "login")
        searchString.set(
            "payload",
            PayloadFormatter.encode({
                step: "login-otp-1",
            }),
        )
        searchString.set("redirect", location.state?.from ?? PATHS.INDEX)

        return (
            <Navigate
                to={{
                    pathname: PATHS.INDEX,
                    search: searchString.toString(),
                }}
                replace
                state={{
                    from: location.state?.from ?? PATHS.INDEX,
                    search: location.state?.search,
                }}
            />
        )
    }, [location.state?.from, location.state?.search])

    return {
        //
        openModalToStep,
        navToStep,
        moveToStep,
        step,
        payload,
        mode,
        setPayload,
        close,
        loginSuccess,
        LoginRedirectNavigate,
    }
}

export function useCallbackLoginAction(...args: Parameters<typeof useCallback>) {
    const { openModalToStep } = useLoginAction()
    const [_callback, deps] = args
    const callback = useCallback(
        () => {
            const token = getToken()
            if (!token?.accessToken) {
                openModalToStep("login-otp-1")
                return
            }
            // @ts-ignore
            return _callback(...callbackArgs)
        },
        // eslint-disable-next-line react-hooks/exhaustive-deps
        [_callback, openModalToStep, ...deps],
    )

    return callback
}
